package com.autotest.nore.common.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.autotest.nore.common.constants.AssertionMethod;
import com.jayway.jsonpath.JsonPath;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AssertionUtils {

    public static boolean assertValue(Object actual, String expect, AssertionMethod method) {
        switch (method) {
            case equals:
                return actual.equals(expect);
            case equalsList:
                return actual instanceof JSONArray && ((JSONArray) actual).equals(JSON.parseArray(expect));
            case equalsDict:
                return actual instanceof JSONObject && ((JSONObject) actual).equals(JSON.parseObject(expect));
            case equalsNumber:
                return actual instanceof Number && Double.parseDouble(actual.toString()) == Double.parseDouble(expect);
            case equalIgnoreCase:
                return actual.toString().equalsIgnoreCase(expect);
            case notEqual:
                return !actual.equals(expect);
            case isGreaterThan:
                return Double.parseDouble(actual.toString()) > Double.parseDouble(expect);
            case isGreaterThanOrEqualTo:
                return Double.parseDouble(actual.toString()) >= Double.parseDouble(expect);
            case isLessThan:
                return Double.parseDouble(actual.toString()) < Double.parseDouble(expect);
            case isLessThanOrEqualTo:
                return Double.parseDouble(actual.toString()) <= Double.parseDouble(expect);
            case isBetween:
                String[] range = expect.split(",");
                double lower = Double.parseDouble(range[0]);
                double upper = Double.parseDouble(range[1]);
                return Double.parseDouble(actual.toString()) >= lower && Double.parseDouble(actual.toString()) <= upper;
            case contains:
                return actual.toString().contains(expect);
            case notContains:
                return !actual.toString().contains(expect);
            case containsOnly:
                return Pattern.matches(expect, actual.toString());
            case isNone:
                return actual == null;
            case notEmpty:
                return actual != null && !actual.toString().isEmpty();
            case empty:
                return actual == null || actual.toString().isEmpty();
            case isTrue:
                return Boolean.parseBoolean(actual.toString());
            case isFalse:
                return !Boolean.parseBoolean(actual.toString());
            case isStrType:
                return actual instanceof String;
            case isIntType:
                return actual instanceof Integer;
            case isFloatType:
                return actual instanceof Float || actual instanceof Double;
            case isInt:
                return actual.toString().matches("\\d+");
            case isLetter:
                return actual.toString().matches("[a-zA-Z]+");
            case isLower:
                return actual.toString().equals(actual.toString().toLowerCase());
            case isUpper:
                return actual.toString().equals(actual.toString().toUpperCase());
            case startWith:
                return actual.toString().startsWith(expect);
            case endWith:
                return actual.toString().endsWith(expect);
            case isIn:
                return expect.contains(actual.toString());
            case isNotIn:
                return !expect.contains(actual.toString());
            case isNotZero:
                return !actual.toString().equals("0");
            case isZero:
                return actual.toString().equals("0");
            case isPositive:
                return Double.parseDouble(actual.toString()) > 0;
            case isNegative:
                return Double.parseDouble(actual.toString()) < 0;
            case isCloseTo:
                String[] tolerance = expect.split(",");
                double value = Double.parseDouble(actual.toString());
                double expectedValue = Double.parseDouble(tolerance[0]);
                double epsilon = Double.parseDouble(tolerance[1]);
                return Math.abs(value - expectedValue) <= epsilon;
            case listLenEqual:
                return JSON.parseArray(String.valueOf(actual)).size() == Integer.parseInt(expect);
            case listLenGreaterThan:
                return JSON.parseArray(String.valueOf(actual)).size() > Integer.parseInt(expect);
            case listLenLessThan:
                return JSON.parseArray(String.valueOf(actual)).size() < Integer.parseInt(expect);
            default:
                throw new IllegalArgumentException("Unknown assertion method: " + method);
        }
    }

    public static Object extractValue(String from, String expression, String method, String source) {
        if ("resBody".equals(from)) {
            if ("jsonpath".equalsIgnoreCase(method)) {
                return JsonPath.read(source, expression);
            } else if ("regular".equalsIgnoreCase(method)) {
                Pattern pattern = Pattern.compile(expression);
                Matcher matcher = pattern.matcher(source);
                if (matcher.find()) {
                    return matcher.group();
                }
            }
        } else if ("resHeader".equals(from)) {
            if ("jsonpath".equalsIgnoreCase(method)) {
                JSONObject headers = JSON.parseObject(source);
                return JsonPath.read(headers, expression);
            } else if ("regular".equalsIgnoreCase(method)) {
                String headerValue = ((JSONObject) JSON.parse(source)).getString(expression.split("\\.")[0]);
                if (headerValue != null) {
                    Pattern pattern = Pattern.compile(expression.split("\\.")[1]);
                    Matcher matcher = pattern.matcher(headerValue);
                    if (matcher.find()) {
                        return matcher.group();
                    }
                }
            }
        } else if ("resCode".equals(from)) {
            return source.equals(expression);
        }
        return null;
    }




}
